Brace expansion¶
Time: O(PxLxLog(PL)); Space: O(PxL); medium*
A string S represents a list of words.
Each letter in the word has 1 or more options.
If there is one option, the letter is represented as is.
If there is more than one option, then curly braces delimit the options.
For example, “{a,b,c}” represents options [“a”, “b”, “c”].
For example, “{a,b,c}d{e,f}” represents the list [“ade”, “adf”, “bde”, “bdf”, “cde”, “cdf”].
Return all words that can be formed in this manner, in lexicographical order.
Example 1:
Input: S = “{a,b}c{d,e}f”
Output: [“acdf”,“acef”,“bcdf”,“bcef”]
Example 2:
Input: S = “abcd”
Output: [“abcd”]
Constraints:
1 <= len(S) <= 50
There are no nested curly brackets.
All characters inside a pair of consecutive opening and ending curly brackets are different.
1. Backtracking¶
Note that the string requires reformatting to divide chars can be backtracking.
[4]:
import itertools
class Solution1(object):
"""
Time: O(P*L*Log(P*L)), P is the production of all number of options , L is the length of a word
Space: O(P*L)
"""
def expand(self, S): # nested is fine
"""
:type S: str
:rtype: List[str]
"""
def form_words(options):
words = list(map(''.join, itertools.product(*options)))
words.sort()
return words
def generate_option(expr, i):
option_set = set()
while i[0] != len(expr) and expr[i[0]] != "}":
i[0] += 1 # { or ,
for option in generate_words(expr, i):
option_set.add(option)
i[0] += 1 # }
option = list(option_set)
option.sort()
return option
def generate_words(expr, i):
options = []
while i[0] != len(expr) and expr[i[0]] not in ",}":
tmp = []
if expr[i[0]] not in "{,}":
tmp.append(expr[i[0]])
i[0] += 1 # a-z
elif expr[i[0]] == "{":
tmp = generate_option(expr, i)
options.append(tmp)
return form_words(options)
return generate_words(S, [0])
[5]:
sol = Solution1()
S = "{a,b}c{d,e}f"
assert sol.expand(S) == ["acdf","acef","bcdf","bcef"]
S = "abcd"
assert sol.expand(S) == ["abcd"]
[6]:
class Solution2(object):
def expand(self, S): # nested is fine
"""
:type S: str
:rtype: List[str]
"""
def form_words(options):
words = []
total = 1
for opt in options:
total *= len(opt)
for i in range(total):
tmp = []
for opt in reversed(options):
i, c = divmod(i, len(opt))
tmp.append(opt[c])
tmp.reverse()
words.append(''.join(tmp))
words.sort()
return words
def generate_option(expr, i):
option_set = set()
while i[0] != len(expr) and expr[i[0]] != "}":
i[0] += 1 # { or ,
for option in generate_words(expr, i):
option_set.add(option)
i[0] += 1 # }
option = list(option_set)
option.sort()
return option
def generate_words(expr, i):
options = []
while i[0] != len(expr) and expr[i[0]] not in ",}":
tmp = []
if expr[i[0]] not in "{,}":
tmp.append(expr[i[0]])
i[0] += 1 # a-z
elif expr[i[0]] == "{":
tmp = generate_option(expr, i)
options.append(tmp)
return form_words(options)
return generate_words(S, [0])
[7]:
sol = Solution2()
S = "{a,b}c{d,e}f"
assert sol.expand(S) == ["acdf","acef","bcdf","bcef"]
S = "abcd"
assert sol.expand(S) == ["abcd"]